#ifndef INC_MATRIX33_H
#define INC_MATRIX33_H

#include "Vector3.h"

namespace gti
{

class quaternion;

class matrix33
{
// column order matrix
// row 1 {11,21,31}
// column 1 {11,12,13}
// vectors are column ordered too, so matrix vector multiplication is
//  11 * v.x + 21 * v.y + 31 * v.z
//  xaxis.x           yaxis.x           zaxis.x
//  xaxis.y           yaxis.y           zaxis.y
//  xaxis.z           yaxis.z           zaxis.z
//  trans.x           trans.y           trans.z

//  11           12           13
//  21           22           23
//  31           32           33
public:
	matrix33(){}
	matrix33(const matrix33& matrix) { set((const float*)matrix.m); }

	// data 
	union
	{
    struct
    {
        float        _11, _12, _13;
        float        _21, _22, _23;
        float        _31, _32, _33;
    };
    float M[3][3];
    float m[9];
  };

	// basic functions
	void identity();
	void reset();

	void transpose();
	bool inverse(matrix33& inverse) const;

	// matrix vector multiplication using a transposed version of the matrix
	void multTranspose(const vector3f& point, vector3f& newpoint) const;

	void orthonormalize();

	float trace() const;
	void getQuaternion(quaternion& q) const;
  
	void set(const float *src);
	void setRow(int row, const vector3f& axis);
	void setColumn(int col, const vector3f& axis);

	void copyRow(int ro, vector3f& row) const;
	void copyColumn(int col, vector3f& column) const;

	void setScaleMatrix(const vector3f& scale);
	
	// useful operators
	matrix33 operator+(const matrix33 &matrix) const;
	matrix33 operator-(const matrix33 &matrix) const;
	matrix33 operator*(const matrix33 &matrix) const;

	matrix33 operator*=(const matrix33 &matrix);
	matrix33 operator*=(const float f);
	friend bool operator == (const matrix33& m1, const matrix33& m2);
	friend bool operator != (const matrix33& m1, const matrix33& m2);

	friend matrix33 operator+(const matrix33& matrix,float f);
	friend matrix33 operator+(float f,const matrix33& matrix);
	friend matrix33 operator-(const matrix33& matrix,float f);
	friend matrix33 operator-(float f,const matrix33& matrix);
	friend matrix33 operator*(const matrix33& matrix,float f);
	friend matrix33 operator*(float f,const matrix33& matrix);
	
	friend vector3f operator*(const matrix33 & matrix, const vector3f& vector);
	// useful conversion
	const float &operator[](int i) const {return m[i];}
	float &operator[](int i) {return m[i];}
	operator float*(void) {return m;}
	float &operator()(int i,int j) {return M[i][j];}
	const float &operator()(int i, int j) const {return M[i][j];}

	const vector3f& axis(int i) const {return (const vector3f&)m[i*3];}
  void setLookAt( vector3f zaxis );

};

};//namespace gti

#endif
